const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

function resolve(filepath) {
  return path.resolve(__dirname, '../', filepath)
}

module.exports = {
  // 入口
  entry: resolve('./src/main.js'),
  // 输出
  output: {
    // 输出文件路径
    path: resolve('dist'),
    // 输出文件名称
    // [name] webpack给打包的模块取一个名字
    // [contenthash:10] 根据文件内容生成一个id值，取10位
    filename: 'js/[name].[contenthash:10].js',
    chunkFilename: 'js/[name].[contenthash:10].js',
    // 给其他资源命名（字体图标）
    assetModuleFilename: 'media/[hash:10][ext][query]',
    clean: true, // 在生成文件之前清空 output 目录
    publicPath: '/'
  },
  
  module: {
    // loader
    rules: [
      // 处理vue文件
      {
        // 哪些文件会被处理
        test: /\.vue$/,
        // 只用一个loader
        loader: 'vue-loader'
      },
      // 处理less文件
      {
        test: /\.less$/,
        // 用多个loader
        // 执行顺序：从右到左
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: ['postcss-preset-env', 'autoprefixer']
              }
            }
          },
          'less-loader'
        ]
      },
      // 处理css文件
      {
        test: /\.css$/,
        // 用多个loader
        // 执行顺序：从右到左
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: ['postcss-preset-env', 'autoprefixer']
              }
            }
          }
        ]
      },
      // 处理scss文件
      {
        test: /\.(scss|sass)$/,
        // 用多个loader
        // 执行顺序：从右到左
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          // css兼容性
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: ['postcss-preset-env', 'autoprefixer']
              }
            }
          },
          'sass-loader'
        ]
      },
      // 处理图片
      {
        test: /\.(png|jpe?g|gif)$/i,
        loader: 'url-loader',
        // 对url-loader进行配置
        options: {
          // 对图片的优化
          // 将小于limit大小的图片会转化成base64格式
          // 优点：减少请求数量
          // 缺点：文件体积会更大
          limit: 10 * 1024,
          // 关闭es6模块化，使用commonjs
          esModule: false,
          name: 'img/[hash:10].[ext]'
        }
      },
      {
        test: /\.js$/,
        // 排除
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              // 能够将ES6普通语法转化成ES5以下的语法
              '@babel/preset-env',
              // 引入ES6复杂语法的兼容性的包
              {
                // 按需加载corejs的内容
                useBuiltIns: 'usage',
                corejs: '3',
                // targets: '> 1%, not dead'
                targets: {
                  chrome: '58',
                  ie: '9',
                  firefox: '30',
                  safari: '8'
                }
              }
            ]
          ],
          // 缓存
          cacheDirectory: true,
          // 将babel打包的辅助代码放一起，打包的体积更小
          plugins: ['@babel/plugin-transform-runtime']
        }
      }
    ]
  },

  plugins: [
    new VueLoaderPlugin(),
    // 处理html文件
    new HtmlWebpackPlugin({
      template: resolve('./public/index.html')
    }),
    // eslint 语法检查
    new ESLintPlugin(),
    // 从js中提取css成单独文件
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:10].css'
    })
  ],
  // 模式
  mode: 'production',

  // 解析
  resolve: {
    // 解决文件路径时，自动补全的文件扩展名
    extensions: ['.vue', '.js', '.json'],
    // 路径别名
    alias: {
      '@': resolve('src'),
      '@api': resolve('src/api')
    }
  },

  optimization: {
    minimize: true,
    minimizer: [
      // 压缩js
      new TerserPlugin({
        exclude: /node_modules/,
        terserOptions: {
          ecma: 5,
          parse: {},
          compress: {},
          mangle: true, // Note `mangle.properties` is `false` by default.
          module: false
          // Deprecated
          // output: null,
          // format: null,
          // toplevel: false,
          // nameCache: null,
          // ie8: true,
          // keep_classnames: undefined,
          // keep_fnames: false,
          // safari10: true
        }
      }),
      // 压缩css
      new CssMinimizerPlugin()
    ],

    splitChunks: {
      chunks: 'all',
      // minSize: 20000,
      // minRemainingSize: 0,
      // minChunks: 1,
      // maxAsyncRequests: 30,
      // maxInitialRequests: 30,
      // enforceSizeThreshold: 50000,
      cacheGroups: {
        vendors: {
          name: 'verdors',
          test: /[\\/]node_modules[\\/]/,
          priority: 20,
          reuseExistingChunk: true
        },
        common: {
          name: 'common',
          test: resolve('src/components'),
          // 要被两个不同的块引入才会被打包
          minChunks: 2,
          priority: 10,
          reuseExistingChunk: true
        }
      }
    }
  },

  devtool: 'source-map'
}
